package com.rem.chat.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rem.chat.common.config.AppConfig;
import com.rem.chat.common.constants.Constants;
import com.rem.chat.common.errcode.ServiceErrorCodeConstants;
import com.rem.chat.common.exception.ServiceException;
import com.rem.chat.common.utils.BeanTransUtil;
import com.rem.chat.common.utils.RedisComponent;
import com.rem.chat.common.utils.RedisUtil;
import com.rem.chat.common.utils.StringUtil;
import com.rem.chat.mapper.*;
import com.rem.chat.pojo.dataobject.*;
import com.rem.chat.pojo.request.UserLoginRequest;
import com.rem.chat.pojo.request.UserRegisterRequest;
import com.rem.chat.service.AccountService;
import com.rem.chat.pojo.response.UserLoginResponse;
import com.rem.chat.service.ContactService;
import com.rem.chat.service.dto.UserLoginDTO;
import com.rem.chat.service.enums.*;
import jakarta.annotation.Resource;
import jodd.util.ArraysUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author: Themberfue
 * @date: 2025/6/4 14:37
 * @description:
 */
@Service
public class AccountServiceImpl implements AccountService {
    @Resource
    UserInfoMapper userInfoMapper;

    @Resource
    UserBeautyIdMapper userBeautyIdMapper;

    @Resource
    UserContactMapper userContactMapper;

    @Resource
    ChatSessionMapper chatSessionMapper;

    @Resource
    ChatSessionUserMapper chatSessionUserMapper;

    @Resource
    ChatMessageMapper chatMessageMapper;

    @Resource
    AppConfig appConfig;

    @Resource
    RedisComponent redisComponent;

    @Resource
    RedisUtil redisUtil;

    @Resource(name = "contactServiceImpl")
    ContactService contactService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(UserRegisterRequest request) {
        // Step 1. 校验邮箱是否被注册
        validateEmailNotRegistered(request.getEmail());

        // Step 2-3: 生成用户ID（处理靓号逻辑）并加密密码
        String userId = genUIdAndUpdateBIdSta(request.getEmail());
        String encryptedPassword = StringUtil.encodeSHA256(request.getPassword());

        // Step 4. 存入数据库
        UserInfoDO userInfoDO = createUserInfo(userId, request, encryptedPassword);
        userInfoMapper.insert(userInfoDO);

        // Step 5. 将自己添加为好友
        addMyselfContact(userId, userInfoDO.getNickName());

        // Step 6. 创建机器人好友
        contactService.addRobotContact(userId);

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserLoginResponse login(UserLoginRequest request) {
        // Step 1-3: 验证用户身份和状态
        UserInfoDO userInfo = validateUserCredentials(request);

        // Step 4: 构造登录信息
        UserLoginDTO userLoginDTO = createLoginDTO(userInfo);

        // Step 5-7: 查询并缓存用户联系人
        List<String> contactIds = fetchUserContacts(userLoginDTO.getUserId());
        cacheUserContacts(userLoginDTO.getUserId(), contactIds);

        // Step 8-10: 处理Token和缓存
        generateAndCacheToken(userLoginDTO);

        // Step 11: 更新用户登录时间
        updateUserLoginTime(userInfo);

        // Step 12. 将数据返回
        return BeanTransUtil.transToUserLoginResponse(userLoginDTO, userInfo);
    }

    private void updateUserLoginTime(UserInfoDO userInfo) {
        userInfo.setLastLoginTime(new Date());
        userInfoMapper.updateById(userInfo);
    }

    private void generateAndCacheToken(UserLoginDTO userLoginDTO) {
        // 校验用户是否已登录
        String lastHeartBeat = redisComponent.getUserHeartBeat(userLoginDTO.getUserId());
        if (StringUtils.hasLength(lastHeartBeat)) {
            throw new ServiceException(ServiceErrorCodeConstants.ACCOUNT_HAD_LOGIN);
        }

        // 生成Token
        String token = StringUtil.encodeMD5(userLoginDTO.getUserId() + StringUtil.getRandomString(Constants.LENGTH_20));
        userLoginDTO.setToken(token);

        // 清理旧Token
        String tmpToken = redisUtil.get(Constants.REDIS_KEY_WS_TOKEN_USERID + userLoginDTO.getUserId());
        if (StringUtils.hasText(tmpToken)) {
            redisUtil.delete(Constants.REDIS_KEY_WS_TOKEN + tmpToken);
        }

        // 缓存新Token
        redisComponent.saveTokenUserInfo(userLoginDTO);
    }

    private void cacheUserContacts(String userId, List<String> contactIds) {
        if (!contactIds.isEmpty()) {
            redisComponent.saveUserContactList(userId, contactIds);
        }
    }

    private List<String> fetchUserContacts(String userId) {
        QueryWrapper<UserContactDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(UserContactDO::getUserId, userId)
                .in(UserContactDO::getStatus, List.of(
                        UserContactStatusEnum.FRIEND.getStatus(),
                        UserContactStatusEnum.BLACKLIST_BE.getStatus(),
                        UserContactStatusEnum.DEL_BE.getStatus()
                ));

        return userContactMapper.selectList(queryWrapper).stream()
                .map(UserContactDO::getContactId)
                .collect(Collectors.toList());
    }

    private UserLoginDTO createLoginDTO(UserInfoDO userInfo) {
        String[] adminEmails = appConfig.getAdminEmails().split(",");
        boolean isAdmin = Arrays.asList(adminEmails).contains(userInfo.getEmail());
        UserLoginDTO dto = new UserLoginDTO();
        dto.setIsAdmin(isAdmin);
        dto.setUserId(userInfo.getUserId());
        dto.setNickName(userInfo.getNickName());
        return dto;
    }

    private UserInfoDO validateUserCredentials(UserLoginRequest request) {
        // 查询用户
        QueryWrapper<UserInfoDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UserInfoDO::getEmail, request.getEmail());
        UserInfoDO userInfo = userInfoMapper.selectOne(queryWrapper);

        // 校验用户存在
        if (userInfo == null) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_IS_NOT_EXISTS);
        }

        // 校验密码
        if (!StringUtil.encodeSHA256(request.getPassword()).equals(userInfo.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_WRONG);
        }

        // 校验用户状态
        if (UserStatusEnum.DISABLE.getStatus().equals(userInfo.getStatus())) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_IS_DISABLE);
        }

        return userInfo;
    }

    private void validateEmailNotRegistered(String email) {
        QueryWrapper<UserInfoDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(UserInfoDO::getEmail, email);
        UserInfoDO userInfo = userInfoMapper.selectOne(queryWrapper);
        if (null != userInfo) {
            throw new ServiceException(ServiceErrorCodeConstants.EMAIL_HAD_USED);
        }
    }

    private String genUIdAndUpdateBIdSta(String email) {
        // 检查是否有可用靓号
        QueryWrapper<UserBeautyIdDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UserBeautyIdDO::getEmail, email);
        UserBeautyIdDO userBeautyId = userBeautyIdMapper.selectOne(queryWrapper);

        boolean hasBeautyId = userBeautyId != null &&
                BeautyAccountStatusEnum.NO_USE.getStatus().equals(userBeautyId.getStatus());

        // Step 更新该靓号状态
        if (hasBeautyId) {
            UserBeautyIdDO userBeautyIdDO = UserBeautyIdDO.builder()
                    .id(userBeautyId.getId())
                    .userId(userBeautyId.getUserId())
                    .status(BeautyAccountStatusEnum.USED.getStatus())
                    .build();
            userBeautyIdMapper.updateById(userBeautyIdDO);
        }

        return hasBeautyId
                ? UserContactTypeEnum.USER.getPrefix() + userBeautyId.getUserId()
                : StringUtil.getUserId();
    }

    private UserInfoDO createUserInfo(String userId, UserRegisterRequest request, String encryptedPassword) {
        return UserInfoDO.builder()
                .userId(userId)
                .email(request.getEmail())
                .password(encryptedPassword)
                .nickName(request.getNickName())
                .joinType(JoinTypeEnum.APPLY.getType())
                .status(UserStatusEnum.ENABLE.getStatus())
                .lastOffTime(System.currentTimeMillis())
                .build();
    }

    private void addMyselfContact(String userId, String nickName) {
        // Step 1. 将自己添加为好友
        UserContactDO userContactDO = UserContactDO.builder()
                .contactType(UserContactTypeEnum.USER.getType())
                .userId(userId)
                .contactId(userId)
                .status(UserContactStatusEnum.FRIEND.getStatus())
                .build();
        userContactMapper.insert(userContactDO);

        String sessionId = StringUtil.getSessionId(new String[]{userId, userId});
        // Step 2. 增加会话消息
        ChatSessionDO chatSessionDO = ChatSessionDO.builder()
                .sessionId(sessionId)
                .lastMessage("")
                .lastReceiveTime(System.currentTimeMillis())
                .build();
        chatSessionMapper.insert(chatSessionDO);

        // Step 3. 增加会话用户信息
        ChatSessionUserDO chatSessionUserDO = ChatSessionUserDO.builder()
                .sessionId(sessionId)
                .userId(userId)
                .contactId(userId)
                .contactName(nickName)
                .build();
        chatSessionUserMapper.insert(chatSessionUserDO);

        // Step 4. 增加聊天信息
        ChatMessageDO chatMessageDO = ChatMessageDO.builder()
                .sessionId(sessionId)
                .messageContent("")
                .messageType(MessageTypeEnum.CHAT.getType())
                .sendUserId(userId)
                .sendUserNickName(nickName)
                .contactId(userId)
                .contactType(UserContactTypeEnum.USER.getType())
                .status(MessageStatusEnum.SENT.getStatus())
                .build();
        chatMessageMapper.insert(chatMessageDO);
    }

}
